package com.getan.boot.common.utils;

import com.getan.boot.common.ResponseCode;
import com.getan.boot.common.exception.BizException;

import java.util.Collection;
import java.util.Map;
import java.util.function.Function;
import java.util.function.Supplier;

/**
 * 条件
 *
 * @author Bruce.Gong
 * @date 2021-05-06
 */
@SuppressWarnings("unused")
public class Preconditions {

    /**
     * 判断 {@code expression} 是否为 {@code true}，如果不为 {@code true}，则抛出 {@code IllegalStateException} 异常，异常描述为 {@code message}
     * <p>
     * 与 {@link #isTrue} 方法类似，两者的差别是抛出的异常类型不一样，{@link #isTrue} 方法抛出的是 {@code IllegalArgumentException} 异常
     *
     * @param expression 条件
     * @param message    异常描述
     * @throws IllegalStateException {@code !expression} 则抛出异常
     */
    public static void state(Supplier<Boolean> expression, String message) {
        check(expression, IllegalStateException::new, message);
    }

    /**
     * 判断 {@code expression} 是否为 {@code true}，如果不为 {@code true}，则抛出 {@code IllegalStateException} 异常，异常描述为 {@code message}
     * <p>
     * 与 {@link #isTrue} 方法类似，两者的差别是抛出的异常类型不一样，{@link #isTrue} 方法抛出的是 {@code IllegalArgumentException} 异常
     *
     * @param expression 条件
     * @param message    异常描述
     * @param params     参数
     * @throws IllegalStateException {@code !expression} 则抛出异常
     */
    public static void state(Supplier<Boolean> expression, String message, Object... params) {
        check(expression, IllegalStateException::new, message, params);
    }

    /**
     * 判断 {@code expression} 是否为 {@code true}，如果不为 {@code true}，则抛出 {@code IllegalStateException} 异常，异常描述为 {@code message}
     * <p>
     * 与 {@link #isTrue} 方法类似，两者的差别是抛出的异常类型不一样，{@link #isTrue} 方法抛出的是 {@code IllegalArgumentException} 异常
     *
     * @param expression 条件
     * @param message    异常描述
     * @throws IllegalStateException {@code !expression} 则抛出异常
     */
    public static void state(Boolean expression, String message) {
        check(() -> !expression, IllegalStateException::new, message);
    }

    /**
     * 判断 {@code expression} 是否为 {@code true}，如果不为 {@code true}，则抛出 {@code IllegalStateException} 异常，异常描述为 {@code message}
     * <p>
     * 与 {@link #isTrue} 方法类似，两者的差别是抛出的异常类型不一样，{@link #isTrue} 方法抛出的是 {@code IllegalArgumentException} 异常
     *
     * @param expression 条件
     * @param message    异常描述
     * @param params     参数
     * @throws IllegalStateException {@code !expression} 则抛出异常
     */
    public static void state(Boolean expression, String message, Object... params) {
        check(() -> !expression, IllegalStateException::new, message, params);
    }

    /**
     * {@code expression === true}，则抛出 {@code ApplicationException} 异常，异常码为 {@code errorCode}
     *
     * @param expression 条件
     * @param errorCode  异常码
     * @param params     参数
     */
    public static void isTrue(Boolean expression, ResponseCode errorCode, Object... params) {
        check(() -> Boolean.TRUE.equals(expression), errorCode, params);
    }

    /**
     * {@code expression === false}，则抛出 {@code ApplicationException} 异常，异常码为 {@code errorCode}
     *
     * @param expression 条件
     * @param errorCode  异常码
     * @param params     参数
     */
    public static void isFalse(Boolean expression, ResponseCode errorCode, Object... params) {
        check(() -> Boolean.FALSE.equals(expression), errorCode, params);
    }

    /**
     * {@code expression == null}，则抛出 {@code ApplicationException} 异常，异常码为 {@code errorCode}
     *
     * @param object    对象
     * @param errorCode 异常码
     * @param params    参数
     */
    public static void isNull(Object object, ResponseCode errorCode, Object... params) {
        check(() -> object == null, errorCode, params);
    }

    /**
     * {@code expression != null}，则抛出 {@code ApplicationException} 异常，异常码为 {@code errorCode}
     *
     * @param object    对象
     * @param errorCode 异常码
     * @param params    参数
     */
    public static void nonNull(Object object, ResponseCode errorCode, Object... params) {
        check(() -> object != null, errorCode, params);
    }

    /**
     * {@code StringUtils.isNotEmpty(text)}，则抛出 {@code ApplicationException} 异常，异常码为 {@code errorCode}
     *
     * @param text      字符串
     * @param errorCode 异常码
     * @param params    参数
     * @see StringUtils#isEmpty
     */
    public static void notEmpty(String text, ResponseCode errorCode, Object... params) {
        check(() -> StringUtils.isNotEmpty(text), errorCode, params);
    }

    /**
     * {@code StringUtils.isEmpty(text)}，则抛出 {@code ApplicationException} 异常，异常码为 {@code errorCode}
     *
     * @param text      字符串
     * @param errorCode 异常码
     * @param params    参数
     * @see StringUtils#isEmpty
     */
    public static void isEmpty(String text, ResponseCode errorCode, Object... params) {
        check(() -> StringUtils.isEmpty(text), errorCode, params);
    }

    /**
     * {@code StringUtils.isNotBlank(text)}，则抛出 {@code ApplicationException} 异常，异常码为 {@code errorCode}
     *
     * @param text      字符串
     * @param errorCode 异常码
     * @param params    参数
     * @see StringUtils#isBlank
     */
    public static void notBlank(String text, ResponseCode errorCode, Object... params) {
        check(() -> StringUtils.isNotBlank(text), errorCode, params);
    }

    /**
     * {@code StringUtils.isBlank(text)}，则抛出 {@code ApplicationException} 异常，异常码为 {@code errorCode}
     *
     * @param text      字符串
     * @param errorCode 异常码
     * @param params    参数
     * @see StringUtils#isBlank
     */
    public static void isBlank(String text, ResponseCode errorCode, Object... params) {
        check(() -> StringUtils.isBlank(text), errorCode, params);
    }

    /**
     * {@code CollectionUtils.isNotEmpty(collection)}，则抛出 {@code ApplicationException} 异常，异常码为 {@code errorCode}
     *
     * @param collection 列表
     * @param errorCode  异常码
     * @param params     参数
     * @see CollectionUtils#isEmpty
     */
    public static void notEmpty(Collection<?> collection, ResponseCode errorCode, Object... params) {
        check(() -> CollectionUtils.isNotEmpty(collection), errorCode, params);
    }

    /**
     * {@code CollectionUtils.isEmpty(collection)}，则抛出 {@code ApplicationException} 异常，异常码为 {@code errorCode}
     *
     * @param collection 列表
     * @param errorCode  异常码
     * @param params     参数
     * @see CollectionUtils#isEmpty
     */
    public static void isEmpty(Collection<?> collection, ResponseCode errorCode, Object... params) {
        check(() -> CollectionUtils.isEmpty(collection), errorCode, params);
    }

    /**
     * {@code CollectionUtils.isNotEmpty(map)}，则抛出 {@code ApplicationException} 异常，异常码为 {@code errorCode}
     *
     * @param map       键值对
     * @param errorCode 异常码
     * @param params    参数
     * @see CollectionUtils#isEmpty
     */
    public static void notEmpty(Map<?, ?> map, ResponseCode errorCode, Object... params) {
        check(() -> CollectionUtils.isNotEmpty(map), errorCode, params);
    }

    /**
     * {@code CollectionUtils.isEmpty(map)}，则抛出 {@code ApplicationException} 异常，异常码为 {@code errorCode}
     *
     * @param map       键值对
     * @param errorCode 异常码
     * @param params    参数
     * @see CollectionUtils#isEmpty
     */
    public static void isEmpty(Map<?, ?> map, ResponseCode errorCode, Object... params) {
        check(() -> CollectionUtils.isEmpty(map), errorCode, params);
    }

    /**
     * {@code ArrayUtils.isNotEmpty(array)}，则抛出 {@code ApplicationException} 异常，异常码为 {@code errorCode}
     *
     * @param array     数组
     * @param errorCode 异常码
     * @param params    参数
     * @see ArrayUtils#isNotEmpty
     */
    public static void notEmpty(Object[] array, ResponseCode errorCode, Object... params) {
        check(() -> ArrayUtils.isNotEmpty(array), errorCode, params);
    }

    /**
     * {@code ArrayUtils.isEmpty(array)}，则抛出 {@code ApplicationException} 异常，异常码为 {@code errorCode}
     *
     * @param array     数组
     * @param errorCode 异常码
     * @param params    参数
     * @see ArrayUtils#isEmpty
     */
    public static void isEmpty(Object[] array, ResponseCode errorCode, Object... params) {
        check(() -> ArrayUtils.isEmpty(array), errorCode, params);
    }

    static String format(String template, Object... args) {
        // null -> "null"
        template = String.valueOf(template);

        if (args == null) {
            return template;
        }

        // start substituting the arguments into the '%s' placeholders
        StringBuilder builder = new StringBuilder(template.length() + 16 * args.length);
        int templateStart = 0;
        int i = 0;
        while (i < args.length) {
            int placeholderStart = template.indexOf("%s", templateStart);
            if (placeholderStart == -1) {
                break;
            }
            builder.append(template, templateStart, placeholderStart);
            builder.append(args[i++]);
            templateStart = placeholderStart + 2;
        }
        builder.append(template, templateStart, template.length());

        // if we run out of placeholders, append the extra args in square braces
        if (i < args.length) {
            builder.append(" [");
            builder.append(args[i++]);
            while (i < args.length) {
                builder.append(", ");
                builder.append(args[i++]);
            }
            builder.append(']');
        }

        return builder.toString();
    }

    /**
     * 如果条件为 true，则抛出指定异常
     *
     * @param expression 条件函数
     * @param exBuilder  异常构造函数
     * @param message    异常信息
     * @param params     异常信息参数
     */
    public static void check(Supplier<Boolean> expression, Function<String, RuntimeException> exBuilder, String message, Object... params) {
        if (expression.get()) {
            throw exBuilder.apply(format(message, params));
        }
    }

    /**
     * 如果条件为 true，则抛出指定异常
     *
     * @param expression 条件函数
     * @param errorCode  异常信息
     * @param params     异常信息参数
     */
    public static void check(Supplier<Boolean> expression, ResponseCode errorCode, Object... params) {
        if (expression.get()) {
            throw new BizException(errorCode, params);
        }
    }

}